package com.xuanwei.core.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.xuanwei.core.entity.ao.ProductAttributeAO;
import com.xuanwei.core.entity.ao.ProductSkuAO;
import com.xuanwei.core.entity.vo.ProductListVo;
import com.xuanwei.core.entity.param.ProductParam;
import com.xuanwei.core.exception.XwException;
import com.xuanwei.core.mq.SendProduct;
import com.xuanwei.core.service.*;
import com.xuanwei.core.util.GenerateUUID;
import com.xuanwei.dao.entity.*;
import com.xuanwei.dao.mapper.XwProductMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author mjy
 * @since 2019-04-25
 */
@Service
public class XwProductServiceImpl extends ServiceImpl<XwProductMapper, XwProduct> implements IXwProductService {


    private IXwProductParamService productParamService;


    private IXwCategoryService categoryService;


    private IXwProductAttributeService productAttributeService;


    private IXwProductAttributeValueService productAttributeValueService;


    private IXwProductSkuService productSkuService;


    private IXwProductLabelService labelService;


    private SendProduct sendProduct;

    public XwProductServiceImpl(IXwProductParamService productParamService,
                                IXwProductAttributeService productAttributeService,
                                IXwProductAttributeValueService productAttributeValueService,
                                IXwProductSkuService productSkuService,
                                IXwProductLabelService labelService,
                                IXwCategoryService categoryService,
                                SendProduct sendProduct) {
        this.productParamService = productParamService;
        this.productAttributeService = productAttributeService;
        this.productAttributeValueService = productAttributeValueService;
        this.productSkuService = productSkuService;
        this.labelService = labelService;
        this.categoryService = categoryService;
        this.sendProduct = sendProduct;
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void add(XwProduct product, Integer operationId, List<XwProductParam> params, List<ProductAttributeAO> productAttributes, List<ProductSkuAO> productSkus) {
        //添加商品的基本信息
        setPrice(product, productSkus);
        product.setCreateTime(LocalDateTime.now());
        product.setUpdateTime(LocalDateTime.now());
        product.setOperationId(operationId);
        product.setProductNo(new Date().getTime() + "");
        XwCategory category = categoryService.getById(product.getCategoryId());
        product.setCategoryName(category.getName());
        //商品标签
        if (product.getLabelId() != null && product.getLabelId() != 0) {
            XwProductLabel productLabel = labelService.getById(product.getLabelId());
            product.setLabelName(productLabel.getName());
        }
        save(product);
        Integer productId = product.getId();

        //添加商品参数
        params.forEach(s -> {
            s.setCreateTime(LocalDateTime.now());
            s.setUpdateTime(LocalDateTime.now());
            s.setProductId(productId);
        });
        productParamService.saveBatch(params);
        List<XwProductAttribute> productAttributeList = Lists.newArrayListWithCapacity(productAttributes.size());
        productAttributes.forEach(s -> {
            //添加商品属性
            XwProductAttribute productAttribute = new XwProductAttribute();
            productAttribute.setProductId(productId);
            productAttribute.setName(s.getName());
            productAttribute.setCreateTime(LocalDateTime.now());
            productAttribute.setUpdateTime(LocalDateTime.now());
            productAttributeService.save(productAttribute);
            productAttributeList.add(productAttribute);
            List<XwProductAttributeValue> productAttributeValues = Lists.newArrayListWithCapacity(s.getValues().size());
            s.getValues().forEach(m -> {
                //添加商品规格
                XwProductAttributeValue productAttributeValue = new XwProductAttributeValue();
                productAttributeValue.setProductAttributeId(productAttribute.getId());
                productAttributeValue.setCreateTime(LocalDateTime.now());
                productAttributeValue.setUpdateTime(LocalDateTime.now());
                productAttributeValue.setValue(m.getName());
                productAttributeValue.setImageUrl(m.getImage());
                productAttributeValues.add(productAttributeValue);
            });
            productAttribute.setProductAttributeValues(productAttributeValues);
            productAttributeValueService.saveBatch(productAttributeValues);
        });

        //添加商品SKU
        List<XwProductSku> xwProductSkus = Lists.newArrayList();
        skuByAttribute(xwProductSkus, productAttributeList, new XwProductAttributeValue[productAttributeList.size()], 0);
        if (xwProductSkus.size() != productSkus.size()) {
            throw new XwException("商品规格错误");
        }
        for (int i = 0; i < xwProductSkus.size(); i++) {
            xwProductSkus.get(i).setAttributeNo(new Date().getTime() + "");
            xwProductSkus.get(i).setProductId(productId);
            xwProductSkus.get(i).setCostPrice(productSkus.get(i).getCostPrice());
            xwProductSkus.get(i).setMarketPrice(productSkus.get(i).getMarketPrice());
            xwProductSkus.get(i).setPrice(productSkus.get(i).getPrice());
            xwProductSkus.get(i).setStock(productSkus.get(i).getStock());
            xwProductSkus.get(i).setStatus(productSkus.get(i).getStatus());
            xwProductSkus.get(i).setSaleNum(productSkus.get(i).getSaleNum());
            xwProductSkus.get(i).setCreateTime(LocalDateTime.now());
            xwProductSkus.get(i).setUpdateTime(LocalDateTime.now());
        }
        productSkuService.saveBatch(xwProductSkus);
    }

    /**
     * 获取最大或最小
     *
     * @param type  -1最小值,1最大值
     * @param lists 列表
     * @return 值
     */
    private BigDecimal getMaxOrMin(Integer type, List<BigDecimal> lists) {
        BigDecimal target = lists.get(0);
        for (int i = 1; i < lists.size(); i++) {
            BigDecimal price = lists.get(i);
            if (price.compareTo(target) == type) {
                target = price;
            }
        }
        return target;
    }

    /**
     * 商品规格实现排列组合(每一次从属性值选一个)
     *
     * @param productSkus       结果集合
     * @param productAttributes 商品属性
     * @param temp              数组缓存每一次的结果
     * @param index             当前的属性值索引
     */
    private void skuByAttribute(List<XwProductSku> productSkus, List<XwProductAttribute> productAttributes, XwProductAttributeValue[] temp, int index) {
        if (index == productAttributes.size()) {
            StringBuilder ids = new StringBuilder();
            StringBuilder values = new StringBuilder();
            for (XwProductAttributeValue productAttributeValue : temp) {
                ids.append(productAttributeValue.getId()).append("-");
                values.append(productAttributeValue.getValue()).append("-");
            }
            XwProductSku productSku = new XwProductSku();
            productSku.setAttributeIds(ids.substring(0, ids.length() - 1));
            productSku.setAttributeValues(values.substring(0, values.length() - 1));
            productSkus.add(productSku);
            return;
        }
        for (XwProductAttributeValue productAttributeValue : productAttributes.get(index).getProductAttributeValues()) {
            temp[index] = productAttributeValue;
            skuByAttribute(productSkus, productAttributes, temp, index + 1);
        }
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public void update(XwProduct product, Integer operationId, List<XwProductParam> params, List<ProductAttributeAO> productAttributes, List<ProductSkuAO> productSkus) {
        XwProduct one = getOne(new QueryWrapper<XwProduct>().select("id").eq("id", product.getId()));
        if (one == null) {
            throw new XwException("商品不存在");
        }
        product.setUpdateTime(LocalDateTime.now());
        product.setOperationId(operationId);
        setPrice(product, productSkus);
        //修改商品
        updateById(product);
        //修改商品标签
        if (product.getLabelId() != null && product.getLabelId() != 0) {
            XwProductLabel productLabel = labelService.getById(product.getLabelId());
            product.setLabelName(productLabel.getName());
        }
        Integer productId = product.getId();
        //删除属性
        List<XwProductAttribute> xwProductAttributes = productAttributeService.list(new QueryWrapper<XwProductAttribute>()
                .select("id,name").eq("product_id", product.getId()));
        productAttributeService.getBaseMapper().deleteBatchIds(
                xwProductAttributes.stream().map(XwProductAttribute::getId).collect(Collectors.toList()));
        //删除规格
        xwProductAttributes.forEach(s ->
                productAttributeValueService.getBaseMapper()
                        .delete(new UpdateWrapper<XwProductAttributeValue>()
                                .eq("product_attribute_id", s.getId()))
        );
        //删除参数
        productParamService.getBaseMapper().delete(new UpdateWrapper<XwProductParam>().eq("product_id", product.getId()));

        //删除SKU
        productSkuService.getBaseMapper().delete(new UpdateWrapper<XwProductSku>().eq("product_id", productId));

        //添加商品参数
        params.forEach(s -> {
            s.setCreateTime(LocalDateTime.now());
            s.setUpdateTime(LocalDateTime.now());
            s.setProductId(productId);
        });
        productParamService.saveBatch(params);
        List<XwProductAttribute> productAttributeList = Lists.newArrayListWithCapacity(productAttributes.size());
        productAttributes.forEach(s -> {
            //添加商品属性
            XwProductAttribute productAttribute = new XwProductAttribute();
            productAttribute.setProductId(productId);
            productAttribute.setName(s.getName());
            productAttribute.setCreateTime(LocalDateTime.now());
            productAttribute.setUpdateTime(LocalDateTime.now());
            productAttributeService.save(productAttribute);
            productAttributeList.add(productAttribute);
            List<XwProductAttributeValue> productAttributeValues = Lists.newArrayListWithCapacity(s.getValues().size());
            s.getValues().forEach(m -> {
                //添加商品规格
                XwProductAttributeValue productAttributeValue = new XwProductAttributeValue();
                productAttributeValue.setProductAttributeId(productAttribute.getId());
                productAttributeValue.setCreateTime(LocalDateTime.now());
                productAttributeValue.setUpdateTime(LocalDateTime.now());
                productAttributeValue.setValue(m.getName());
                productAttributeValue.setImageUrl(m.getImage());
                productAttributeValues.add(productAttributeValue);
            });
            productAttribute.setProductAttributeValues(productAttributeValues);
            productAttributeValueService.saveBatch(productAttributeValues);
        });

        //添加商品SKU
        List<XwProductSku> xwProductSkus = Lists.newArrayList();
        skuByAttribute(xwProductSkus, productAttributeList, new XwProductAttributeValue[productAttributeList.size()], 0);
        if (xwProductSkus.size() != productSkus.size()) {
            throw new XwException("商品规格错误");
        }
        for (int i = 0; i < xwProductSkus.size(); i++) {
            xwProductSkus.get(i).setAttributeNo(GenerateUUID.getUUID());
            xwProductSkus.get(i).setProductId(productId);
            xwProductSkus.get(i).setCostPrice(productSkus.get(i).getCostPrice());
            xwProductSkus.get(i).setMarketPrice(productSkus.get(i).getMarketPrice());
            xwProductSkus.get(i).setPrice(productSkus.get(i).getPrice());
            xwProductSkus.get(i).setStock(productSkus.get(i).getStock());
            xwProductSkus.get(i).setStatus(productSkus.get(i).getStatus());
            xwProductSkus.get(i).setSaleNum(productSkus.get(i).getSaleNum());
            xwProductSkus.get(i).setCreateTime(LocalDateTime.now());
            xwProductSkus.get(i).setUpdateTime(LocalDateTime.now());
        }
        productSkuService.saveBatch(xwProductSkus);
        sendProduct.update(productId);
    }

    /**
     * 根据SKU设置基本信息的数据
     *
     * @param product     商品
     * @param productSkus 商品SKU
     */
    private void setPrice(XwProduct product, List<ProductSkuAO> productSkus) {
        DecimalFormat decimalFormat = new DecimalFormat("0.00");
        product.setSaleNum(productSkus.stream().mapToInt(ProductSkuAO::getSaleNum).sum());
        product.setStock(productSkus.stream().mapToInt(ProductSkuAO::getStock).sum());
        List<BigDecimal> priceList = productSkus.stream().map(ProductSkuAO::getPrice).collect(Collectors.toList());
        product.setMaxPrice(getMaxOrMin(1, priceList));
        product.setMinPrice(getMaxOrMin(-1, priceList));
        if (product.getMaxPrice().compareTo(product.getMinPrice()) == 0) {
            product.setPrice(decimalFormat.format(product.getMinPrice()));
        } else {
            product.setPrice(decimalFormat.format(product.getMinPrice()) + "-" + decimalFormat.format(product.getMaxPrice()));
        }
        List<BigDecimal> MarketPriceList = productSkus.stream().map(ProductSkuAO::getMarketPrice).collect(Collectors.toList());
        product.setMaxMarketPrice(getMaxOrMin(1, MarketPriceList));
        product.setMinMarketPrice(getMaxOrMin(-1, MarketPriceList));
        if (product.getMaxMarketPrice().compareTo(product.getMinMarketPrice()) == 0) {
            product.setMarketPrice(decimalFormat.format(product.getMinMarketPrice()));
        } else {
            product.setMarketPrice(decimalFormat.format(product.getMinMarketPrice()) + "-" + decimalFormat.format(product.getMaxMarketPrice()));
        }
    }

    @Override
    public void handleStatus(Integer productId) {
        XwProduct product = getBaseMapper().selectOne(new QueryWrapper<XwProduct>()
                .select("id,`status`").eq("id", productId));
        if (product == null) {
            throw new XwException("该商品不存在");
        }
        product.setStatus(product.getStatus() == 0 ? 1 : 0);
        updateById(product);
        if (product.getStatus() == 0) {
            sendProduct.update(productId);
        } else {
            sendProduct.delete(productId);
        }

    }

    @Override
    public Page<ProductListVo> findPage(Page<XwProduct> page, String name, Integer status, Integer orderBy) {
        QueryWrapper<XwProduct> wrapper = new QueryWrapper<>();
        wrapper.select("id,`name`,main_image,price,label_id,label_name,product_no,stock,sale_num,`status`,create_time");
        if (StringUtils.isNotEmpty(name)) {
            wrapper.like("`name`", name);
        }
        if (status != null) {
            wrapper.eq("`status`", status);
        }
        if (orderBy != null) {
            if (orderBy.equals(1)) {
                //创建时间
                wrapper.orderByDesc("create_time");
            } else if (orderBy.equals(2)) {
                //销量
                wrapper.orderByDesc("sale_num");
            } else if (orderBy.equals(3)) {
                //库存
                wrapper.orderByDesc("stock");
            } else if (orderBy.equals(4)) {
                //最低价格
                wrapper.orderByDesc("min_price");
            }
        }
        getBaseMapper().selectPage(page, wrapper);
        Page<ProductListVo> pageData = new Page<>(page.getCurrent(), page.getSize());
        pageData.setTotal(page.getTotal());
        pageData.setPages(page.getPages());
        List<ProductListVo> productListVOS = Lists.newArrayListWithCapacity(page.getRecords().size());
        page.getRecords().forEach(s -> {
            ProductListVo productListVO = new ProductListVo();
            BeanUtils.copyProperties(s, productListVO);
            productListVO.setLabelId(productListVO.getLabelId() == 0 ? null : productListVO.getLabelId());
            productListVOS.add(productListVO);
        });
        pageData.setRecords(productListVOS);
        return pageData;
    }

    @Override
    public ProductParam editDetail(Integer id) {
        XwProduct product = getById(id);
        if (product == null) {
            throw new XwException("商品不存在");
        }
        product.setLabelId(product.getLabelId() == 0 ? null : product.getLabelId());
        ProductParam productParam = new ProductParam();
        productParam.setProduct(product);

        List<XwProductParam> productParams = productParamService.list(new QueryWrapper<XwProductParam>()
                .select("id,param,value").eq("product_id", id));
        productParam.setParams(productParams);
        List<XwProductAttribute> productAttributes = productAttributeService.list(new QueryWrapper<XwProductAttribute>().select("id,name").eq("product_id", id));
        List<ProductAttributeAO> productAttributeAOS = Lists.newArrayListWithCapacity(productAttributes.size());
        productAttributes.forEach(s -> {
            Integer attrId = s.getId();
            ProductAttributeAO productAttributeAO = new ProductAttributeAO();
            productAttributeAO.setId(attrId);
            productAttributeAO.setName(s.getName());
            List<XwProductAttributeValue> productAttributeValues = productAttributeValueService.list(new QueryWrapper<XwProductAttributeValue>()
                    .select("id,value,image_url").eq("product_attribute_id", s.getId()));
            List<ProductAttributeAO.AttributeValue> values = Lists.newArrayListWithCapacity(productAttributeValues.size());
            productAttributeValues.forEach(i -> {
                ProductAttributeAO.AttributeValue attributeValue = new ProductAttributeAO.AttributeValue();
                attributeValue.setId(i.getId());
                attributeValue.setName(i.getValue());
                attributeValue.setImage(i.getImageUrl());
                values.add(attributeValue);
            });
            productAttributeAO.setValues(values);
            productAttributeAOS.add(productAttributeAO);
        });
        productParam.setProductAttributes(productAttributeAOS);
        List<ProductSkuAO> productSkuAOS = findSkuByProductId(id);
        productParam.setProductSkus(productSkuAOS);
        return productParam;
    }

    @Override
    public void updateLabel(Integer id, Integer labelId) {
        XwProduct product = new XwProduct();
        if (labelId != null) {
            XwProductLabel productLabel = labelService.getById(labelId);
            product.setLabelId(labelId);
            product.setLabelName(productLabel.getName());
        } else {
            product.setLabelId(0);
            product.setLabelName("");
        }
        product.setId(id);
        updateById(product);
    }

    @Override
    public List<ProductSkuAO> findSkuByProductId(Integer id) {

        List<XwProductSku> productSkus = productSkuService.list(new QueryWrapper<XwProductSku>().eq("product_id", id));
        List<ProductSkuAO> productSkuAOS = Lists.newArrayListWithCapacity(productSkus.size());
        productSkus.forEach(s -> {
            ProductSkuAO productSkuAO = new ProductSkuAO();
            BeanUtils.copyProperties(s, productSkuAO);
            String[] ids = s.getAttributeIds().split("-");
            List<ProductSkuAO.SkuName> skuNames = Lists.newArrayListWithCapacity(ids.length);
            for (String valueId : ids) {
                XwProductAttributeValue productAttributeValue = productAttributeValueService.getById(Integer.parseInt(valueId));
                String value = productAttributeValue.getValue();
                Integer productAttributeId = productAttributeValue.getProductAttributeId();
                XwProductAttribute productAttribute = productAttributeService.getById(productAttributeId);
                String name = productAttribute.getName();
                ProductSkuAO.SkuName skuName = new ProductSkuAO.SkuName();
                skuName.setName(name);
                skuName.setValue(value);
                skuNames.add(skuName);
            }
            productSkuAO.setSkuName(skuNames);
            productSkuAOS.add(productSkuAO);
        });
        return productSkuAOS;
    }

    /**
     * 根据商品SKU修改商品的价格
     *
     * @param productId   商品ID
     * @param operationId 操作ID
     */
    private void updateProductBySku(Integer productId, Integer operationId) {
        DecimalFormat decimalFormat = new DecimalFormat("0.00");
        List<XwProductSku> productSkus = productSkuService.list(new QueryWrapper<XwProductSku>().eq("product_id", productId));
        XwProduct product = new XwProduct();
        product.setId(productId);
        product.setOperationId(operationId);
        product.setUpdateTime(LocalDateTime.now());
        List<BigDecimal> marketPriceList = productSkus.stream().map(XwProductSku::getMarketPrice).collect(Collectors.toList());
        BigDecimal minMarketPrice = getMaxOrMin(-1, marketPriceList);
        BigDecimal maxMarketPrice = getMaxOrMin(1, marketPriceList);
        product.setMinMarketPrice(minMarketPrice);
        product.setMaxMarketPrice(maxMarketPrice);
        if (minMarketPrice.compareTo(maxMarketPrice) == 0) {
            product.setMarketPrice(decimalFormat.format(minMarketPrice));
        } else {
            product.setMarketPrice(decimalFormat.format(minMarketPrice) + "-" + decimalFormat.format(maxMarketPrice));
        }
        List<BigDecimal> priceList = productSkus.stream().map(XwProductSku::getPrice).collect(Collectors.toList());
        BigDecimal minPrice = getMaxOrMin(-1, priceList);
        BigDecimal maxPrice = getMaxOrMin(1, priceList);
        product.setMinPrice(minPrice);
        product.setMaxPrice(maxPrice);
        if (minPrice.compareTo(maxMarketPrice) == 0) {
            product.setPrice(decimalFormat.format(minPrice));
        } else {
            product.setPrice(decimalFormat.format(minPrice) + "-" + decimalFormat.format(maxPrice));
        }
        product.setStock(productSkus.stream().mapToInt(XwProductSku::getStock).sum());
        product.setSaleNum(productSkus.stream().mapToInt(XwProductSku::getSaleNum).sum());
        updateById(product);
    }

    @Override
    public void updateSku(XwProductSku productSku, Integer operationId) {
        XwProductSku byId = productSkuService.getById(productSku.getId());
        if (byId == null) {
            throw new XwException("该SKU不存在");
        }
        productSkuService.updateById(productSku);
        updateProductBySku(byId.getProductId(), operationId);
        sendProduct.update(byId.getProductId());
    }

    @Override
    public void updateSkuStatus(Integer skuId) {
        XwProductSku productSku = productSkuService.getOne(new QueryWrapper<XwProductSku>()
                .select("id,`status`,product_id").eq("id", skuId));
        if (productSku == null) {
            throw new XwException("该SKU不存在");
        }
        productSku.setStatus(productSku.getStatus() == 0 ? 1 : 0);
        productSku.setUpdateTime(LocalDateTime.now());
        productSkuService.updateById(productSku);
        sendProduct.update(productSku.getProductId());
    }

    @Override
    public List<XwProductParam> findParams(Integer id) {

        List<XwProductParam> productParams = productParamService.list(new QueryWrapper<XwProductParam>()
                .select("id,param,value")
                .eq("product_id", id));
        if (productParams == null || productParams.size() == 0) {
            throw new XwException("商品参数不存在");
        }
        return productParams;
    }

    @Override
    public String findDetail(Integer id) {
        XwProduct product = getById(id);
        if (product == null) {
            throw new XwException("商品不存在");
        }
        return product.getDetail();
    }

    @Override
    public void updateParams(Integer type, Integer id, Integer productId, String name, String value) {

        if (type == 1) {
            XwProductParam productParam = new XwProductParam();
            productParam.setProductId(productId);
            productParam.setParam(name);
            productParam.setValue(value);
            productParam.setUpdateTime(LocalDateTime.now());
            productParam.setCreateTime(LocalDateTime.now());
            productParamService.save(productParam);
        } else if (type == 2) {
            productParamService.getBaseMapper().deleteById(id);
        } else if (type == 3) {
            XwProductParam productParam = new XwProductParam();
            productParam.setId(id);
            productParam.setParam(name);
            productParam.setValue(value);
            productParam.setUpdateTime(LocalDateTime.now());
            productParamService.updateById(productParam);
        }
    }

    @Override
    public void updateDetail(Integer id, String detail, Integer operationId) {
        XwProduct product = new XwProduct();
        product.setId(id);
        product.setDetail(detail);
        product.setOperationId(operationId);
        product.setUpdateTime(LocalDateTime.now());
        updateById(product);
        sendProduct.update(id);
    }

}
